

/* Includes ------------------------------------------------------------------*/
#include "ILI9341_STM32_Driver.h"
#include "spi.h"
#include "gpio.h"
#include <stdint.h>
/* Global Variables ------------------------------------------------------------------*/
volatile uint16_t LCD_HEIGHT = ILI9341_SCREEN_HEIGHT;
volatile uint16_t LCD_WIDTH	 = ILI9341_SCREEN_WIDTH;

static void lcd_setup_address(uint8_t command);
static void lcd_send_data(const unsigned char* data, uint16_t size);


/**
 * @brief 初始化ILI9341的SPI通信
 *
 * 此函数用于初始化ILI9341显示屏的SPI通信，并初始化相关GPIO端口。
 */
void ILI9341_SPI_Init(void)
{
MX_SPI1_Init();																							//SPI INIT
MX_GPIO_Init();																							//GPIO INIT
LCD_CS_L();	//CS OFF
}

/*Send data (char) to LCD*/
/**
 * @brief 向ILI9341屏幕发送SPI数据
 *
 * 使用SPI接口向ILI9341屏幕发送一个字节的数据。
 *
 * @param SPI_Data 要发送的SPI数据
 */
void ILI9341_SPI_Send(unsigned char SPI_Data)
{
	// HAL_SPI_Transmit(HSPI_INSTANCE, &SPI_Data, 1, 1);
	HAL_SPI_Transmit(HSPI_INSTANCE, &SPI_Data, 1,1);
}

/* Send command (char) to LCD */
/**
 * @brief 向ILI9341屏幕写入命令
 *
 * 向ILI9341屏幕写入指定的命令。
 *
 * @param Command 要写入的命令
 */
void ILI9341_Write_Command(uint8_t Command)
{
LCD_CS_L();
LCD_DC_L();	
ILI9341_SPI_Send(Command);
LCD_CS_H();	
}

/* Send Data (char) to LCD */
/**
 * @brief 向ILI9341写入数据
 *
 * 向ILI9341屏幕写入一个字节的数据。
 *
 * @param Data 要写入的数据
 */
void ILI9341_Write_Data(uint8_t Data)
{
LCD_DC_H();
LCD_CS_L();
ILI9341_SPI_Send(Data);	
LCD_CS_H();
}





/* Set Address - Location block - to draw into */
/**
 * @brief 设置ILI9341屏幕地址
 *
 * 将指定的坐标范围设置为ILI9341屏幕的显示地址。
 *
 * @param X1 起始X坐标（高8位）
 * @param Y1 起始Y坐标（高8位）
 * @param X2 结束X坐标（高8位）
 * @param Y2 结束Y坐标（高8位）
 */
void ILI9341_Set_Address(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2)
{
ILI9341_Write_Command(0x2A);
ILI9341_Write_Data(X1>>8);
ILI9341_Write_Data(X1);
ILI9341_Write_Data(X2>>8);
ILI9341_Write_Data(X2);

ILI9341_Write_Command(0x2B);
ILI9341_Write_Data(Y1>>8);
ILI9341_Write_Data(Y1);
ILI9341_Write_Data(Y2>>8);
ILI9341_Write_Data(Y2);

ILI9341_Write_Command(0x2C);
}

/*HARDWARE RESET*/
/**
 * @brief 重置ILI9341屏幕
 *
 * 该函数用于重置ILI9341屏幕。首先，它会点亮LED3作为提示，等待一段时间，然后拉低LCD_CS引脚，
 * 再次等待一段时间，最后关闭LED3。完成这些操作后，ILI9341屏幕将被重置。
 */
void ILI9341_Reset(void)
{
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
HAL_Delay(200);
LCD_CS_L();
HAL_Delay(200);
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);	
}

/*Ser rotation of the screen - changes x0 and y0*/
/**
 * @brief 设置ILI9341屏幕旋转
 *
 * 将指定的旋转值写入ILI9341屏幕，并设置相应的屏幕宽度和高度。
 *
 * @param Rotation 旋转值
 */
void ILI9341_Set_Rotation(uint8_t Rotation) 
{
	// 旋转值赋值给screen_rotation变量
	uint8_t screen_rotation = Rotation;

	// 写入旋转指令到ILI9341
	ILI9341_Write_Command(0x36);
	HAL_Delay(1);

	// 根据screen_rotation的值进行条件判断
	switch(screen_rotation) 
	{
		case SCREEN_VERTICAL_1:
			// 设置屏幕为垂直方向，并设置宽度和高度
			ILI9341_Write_Data(0x40|0x08);
			LCD_WIDTH = 240;
			LCD_HEIGHT = 320;
			break;
		case SCREEN_HORIZONTAL_1:
			// 设置屏幕为水平方向，并设置宽度和高度
			ILI9341_Write_Data(0x20|0x08);
			LCD_WIDTH  = 320;
			LCD_HEIGHT = 240;
			break;
		case SCREEN_VERTICAL_2:
			// 设置屏幕为垂直方向（另一种情况），并设置宽度和高度
			ILI9341_Write_Data(0x80|0x08);
			LCD_WIDTH  = 240;
			LCD_HEIGHT = 320;
			break;
		case SCREEN_HORIZONTAL_2:
			// 设置屏幕为水平方向（另一种情况），并设置宽度和高度
			ILI9341_Write_Data(0x40|0x80|0x20|0x08);
			LCD_WIDTH  = 320;
			LCD_HEIGHT = 240;
			break;
		default:
			// 如果屏幕旋转值无效，则退出
			//EXIT IF SCREEN ROTATION NOT VALID!
			break;
	}
}


/**
 * @brief 启用ILI9341屏幕
 *
 * 打开屏幕背光，并点亮LED2，表示屏幕已启用。
 */
void ILI9341_Enable(void)
{
	HAL_GPIO_WritePin(LCD_LED_GPIO_Port, LCD_LED_Pin, GPIO_PIN_SET);	//打开屏幕背光
	HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);			//点亮LED2,表示屏幕已启用
}

/*Initialize LCD display*/
/**
 * @brief 初始化ILI9341屏幕
 *
 * 初始化ILI9341屏幕，设置必要的参数和命令。
 */
void ILI9341_Init(void)
{


ILI9341_SPI_Init();
ILI9341_Reset();

//SOFTWARE RESET
ILI9341_Write_Command(0x01);
HAL_Delay(1000);
	
//POWER CONTROL A
ILI9341_Write_Command(0xCB);
ILI9341_Write_Data(0x39);
ILI9341_Write_Data(0x2C);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0x34);
ILI9341_Write_Data(0x02);

//POWER CONTROL B
ILI9341_Write_Command(0xCF);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0xC1);
ILI9341_Write_Data(0x30);

//DRIVER TIMING CONTROL A
ILI9341_Write_Command(0xE8);
ILI9341_Write_Data(0x85);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0x78);

//DRIVER TIMING CONTROL B
ILI9341_Write_Command(0xEA);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0x00);

//POWER ON SEQUENCE CONTROL
ILI9341_Write_Command(0xED);
ILI9341_Write_Data(0x64);
ILI9341_Write_Data(0x03);
ILI9341_Write_Data(0x12);
ILI9341_Write_Data(0x81);

//PUMP RATIO CONTROL
ILI9341_Write_Command(0xF7);
ILI9341_Write_Data(0x20);

//POWER CONTROL,VRH[5:0]
ILI9341_Write_Command(0xC0);
ILI9341_Write_Data(0x23);

//POWER CONTROL,SAP[2:0];BT[3:0]
ILI9341_Write_Command(0xC1);
ILI9341_Write_Data(0x10);

//VCM CONTROL
ILI9341_Write_Command(0xC5);
ILI9341_Write_Data(0x3E);
ILI9341_Write_Data(0x28);

//VCM CONTROL 2
ILI9341_Write_Command(0xC7);
ILI9341_Write_Data(0x86);

//MEMORY ACCESS CONTROL
ILI9341_Write_Command(0x36);
ILI9341_Write_Data(0x48);

//PIXEL FORMAT
ILI9341_Write_Command(0x3A);
ILI9341_Write_Data(0x55);

//FRAME RATIO CONTROL, STANDARD RGB COLOR
ILI9341_Write_Command(0xB1);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0x18);

//DISPLAY FUNCTION CONTROL
ILI9341_Write_Command(0xB6);
ILI9341_Write_Data(0x08);
ILI9341_Write_Data(0x82);
ILI9341_Write_Data(0x27);

//3GAMMA FUNCTION DISABLE
ILI9341_Write_Command(0xF2);
ILI9341_Write_Data(0x00);

//GAMMA CURVE SELECTED
ILI9341_Write_Command(0x26);
ILI9341_Write_Data(0x01);

//POSITIVE GAMMA CORRECTION
ILI9341_Write_Command(0xE0);
ILI9341_Write_Data(0x0F);
ILI9341_Write_Data(0x31);
ILI9341_Write_Data(0x2B);
ILI9341_Write_Data(0x0C);
ILI9341_Write_Data(0x0E);
ILI9341_Write_Data(0x08);
ILI9341_Write_Data(0x4E);
ILI9341_Write_Data(0xF1);
ILI9341_Write_Data(0x37);
ILI9341_Write_Data(0x07);
ILI9341_Write_Data(0x10);
ILI9341_Write_Data(0x03);
ILI9341_Write_Data(0x0E);
ILI9341_Write_Data(0x09);
ILI9341_Write_Data(0x00);

//NEGATIVE GAMMA CORRECTION
ILI9341_Write_Command(0xE1);
ILI9341_Write_Data(0x00);
ILI9341_Write_Data(0x0E);
ILI9341_Write_Data(0x14);
ILI9341_Write_Data(0x03);
ILI9341_Write_Data(0x11);
ILI9341_Write_Data(0x07);
ILI9341_Write_Data(0x31);
ILI9341_Write_Data(0xC1);
ILI9341_Write_Data(0x48);
ILI9341_Write_Data(0x08);
ILI9341_Write_Data(0x0F);
ILI9341_Write_Data(0x0C);
ILI9341_Write_Data(0x31);
ILI9341_Write_Data(0x36);
ILI9341_Write_Data(0x0F);

//EXIT SLEEP
ILI9341_Write_Command(0x11);
HAL_Delay(120);

//TURN ON DISPLAY
ILI9341_Write_Command(0x29);

//STARTING ROTATION

ILI9341_Set_Rotation(SCREEN_HORIZONTAL_1);  //设置屏幕旋转方向

ILI9341_Enable();

}

//INTERNAL FUNCTION OF LIBRARY, USAGE NOT RECOMENDED, USE Draw_Pixel INSTEAD
/*Sends single pixel colour information to LCD*/
/**
 * @brief 绘制颜色
 *
 * 向ILI9341屏幕发送颜色值进行绘制。
 *
 * @param Colour 颜色值
 */
void ILI9341_Draw_Colour(uint16_t Colour)
{
    // Sends the colour value over SPI to the display.
    unsigned char TempBuffer[2] = {(Colour >> 8) & 0xFF, Colour & 0xFF};
    
    // Set the data/command selection line to indicate data is being sent.
    LCD_DC_H();
    
    // Enable the chip select line before sending data.
    LCD_CS_L();

    // Send the colour data over SPI.
    HAL_SPI_Transmit(HSPI_INSTANCE, TempBuffer, 2, 1);

    // Disable the chip select line after sending data.
    LCD_CS_H();
}




















//INTERNAL FUNCTION OF LIBRARY
/*Sends block colour information to LCD*/
/**
 * @brief 绘制彩色爆发效果
 *
 * 在ILI9341液晶显示屏上绘制彩色爆发效果。
 *
 * @param Colour 颜色值
 * @param Size 爆发效果的大小
 */

// INTERNAL FUNCTION OF LIBRARY
/*Sends block colour information to LCD*/


/**
 * @brief 连续发送多个相同颜色值
 *
 * 连续发送指定数量的相同颜色值，用于快速填充。
 *
 * @param Colour 颜色值
 * @param Size 需要发送的颜色值的数量
 */
void ILI9341_Draw_Colour_Burst(uint16_t Colour, uint32_t Size)
{
    // 拆分颜色值
    unsigned char TempBuffer[2] = {(Colour >> 8) & 0xFF, Colour & 0xFF};

    // Set the data/command selection line to indicate data is being sent.
    LCD_DC_H();
    
    // Enable the chip select line before sending data.
    LCD_CS_L();

    // 发送颜色数据
    for (uint32_t i = 0; i < Size; i++) {
        HAL_SPI_Transmit(HSPI_INSTANCE, TempBuffer, 2, 1);
    }

    // Disable the chip select line after sending data.
    LCD_CS_H();
}


/*
void ILI9341_Draw_Colour_Burst(uint16_t Colour, uint32_t Size)
{
    //SENDS COLOUR
    uint32_t Buffer_Size = 0;
    if((Size*2) < BURST_MAX_SIZE)
    {
        Buffer_Size = Size;
    }
    else
    {
        Buffer_Size = BURST_MAX_SIZE;
    }
    
    // 设置数据模式
    LCD_DC_H();   
    // 使能LCD CS
    LCD_CS_L();

    // 将颜色值右移8位，以获取高字节
    unsigned char high_byte = Colour >> 8;
    // 创建颜色缓冲区
    unsigned char burst_buffer[Buffer_Size];
    // 初始化整个数组
    for(uint32_t j = 0; j < Buffer_Size; j+=2)
    {
        burst_buffer[j] = high_byte; // 高字节
        burst_buffer[j+1] = (unsigned char)Colour; // 低字节
    }

    // 计算要发送的总大小
    uint32_t Sending_Size = Size*2;
    // 计算需要发送的完整块数量
    uint32_t Sending_in_Block = Sending_Size / Buffer_Size;
    // 计算最后一个块的剩余大小
    uint32_t Remainder_from_block = Sending_Size % Buffer_Size;

    // 发送完整的块
    if(Sending_in_Block != 0)
    {
        for(uint32_t j = 0; j < Sending_in_Block; j++)
        {
            HAL_StatusTypeDef status = HAL_SPI_Transmit(HSPI_INSTANCE, (unsigned char *)burst_buffer, Buffer_Size, 10);	
            if(status != HAL_OK)
            {
                // 错误处理
                // 可以在这里添加错误处理代码
                HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
				break;
            }
        }
    }

    // 发送剩余的数据
    HAL_StatusTypeDef status = HAL_SPI_Transmit(HSPI_INSTANCE, (unsigned char *)burst_buffer, Remainder_from_block, 10);	
    if(status != HAL_OK)
    {
        // 错误处理
        // 可以在这里添加错误处理代码
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
    }

    // 禁用LCD CS
    LCD_CS_H();
}
*/




//FILL THE ENTIRE SCREEN WITH SELECTED COLOUR (either #define-d ones or custom 16bit)
/*Sets address (entire screen) and Sends Height*Width ammount of colour information to LCD*/
/**
 * @brief 填充屏幕
 *
 * 将整个屏幕填充为指定的颜色。
 *
 * @param Colour 颜色值
 */
void ILI9341_Fill_Screen(uint16_t Colour)
{
    // 设置屏幕显示区域为整个屏幕
    ILI9341_Set_Address(0,0,LCD_WIDTH,LCD_HEIGHT);

    // 防止整数溢出
    uint32_t totalPixels = (uint32_t)LCD_WIDTH * (uint32_t)LCD_HEIGHT;

    // 使用指定的颜色填充整个屏幕
    ILI9341_Draw_Colour_Burst(Colour, totalPixels);
}



/**
 * @brief 在ILI9341屏幕上高效填充一个矩形区域
 *
 * 在ILI9341屏幕上从指定的起点到终点高效填充一个矩形区域，并指定填充颜色。
 *
 * @param X1 矩形左上角的X坐标
 * @param Y1 矩形左上角的Y坐标
 * @param X2 矩形右下角的X坐标
 * @param Y2 矩形右下角的Y坐标
 * @param Colour 填充的颜色
 */
void ILI9341_Fill_Rectangle_Efficient(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2, uint16_t Colour)
{
    // 设置矩形区域
    ILI9341_Set_Address(X1, Y1, X2, Y2);

    // 计算矩形的宽度和高度
    uint16_t Width = X2 - X1 + 1;
    uint16_t Height = Y2 - Y1 + 1;

    // 发送颜色数据
    unsigned char TempBuffer[2] = {(Colour >> 8) & 0xFF, Colour & 0xFF};

    // Set the data/command selection line to indicate data is being sent.
    LCD_DC_H();
    
    // Enable the chip select line before sending data.
    LCD_CS_L();

    // 计算总共需要发送的数据量
    uint32_t TotalPixels = Width * Height;

    // 发送颜色数据
    for (uint32_t i = 0; i < TotalPixels; i++) {
        HAL_SPI_Transmit(HSPI_INSTANCE, TempBuffer, 2, 1);
    }

    // Disable the chip select line after sending data.
    LCD_CS_H();
}
























/**
 * @brief 在ILI9341屏幕上绘制一个像素点
 *
 * 在ILI9341屏幕上指定的位置绘制一个像素点，并设置其颜色。
 *
 * @param X 像素点的X坐标
 * @param Y 像素点的Y坐标
 * @param Colour 像素点的颜色值
 */

/**
 * @brief 绘制单个像素点
 * 
 * @param X 像素的X坐标
 * @param Y 像素的Y坐标
 * @param Colour 像素的颜色值
 */
void ILI9341_Draw_Pixel(uint16_t X,uint16_t Y,uint16_t Colour) 
{
    if(X >= LCD_WIDTH || Y >= LCD_HEIGHT) return; // OUT OF BOUNDS!

    lcd_setup_address(0x2A); // XDATA
    static unsigned char temp_buffer_x[4];
    temp_buffer_x[0] = X >> 8;
    temp_buffer_x[1] = X & 0xFF;
    temp_buffer_x[2] = (X + 1) >> 8;
    temp_buffer_x[3] = (X + 1) & 0xFF;
    lcd_send_data(temp_buffer_x, 4);

    lcd_setup_address(0x2B); // YDATA
    static unsigned char temp_buffer_y[4];
    temp_buffer_y[0] = Y >> 8;
    temp_buffer_y[1] = Y & 0xFF;
    temp_buffer_y[2] = (Y + 1) >> 8;
    temp_buffer_y[3] = (Y + 1) & 0xFF;
    lcd_send_data(temp_buffer_y, 4);

    lcd_setup_address(0x2C); // COLOUR
    static unsigned char temp_buffer_color[2];
    temp_buffer_color[0] = Colour >> 8;
    temp_buffer_color[1] = Colour & 0xFF;
    lcd_send_data(temp_buffer_color, 2);
}

static void lcd_setup_address(uint8_t command)
{
    LCD_DC_L();    
    LCD_CS_L();
    ILI9341_SPI_Send(command);
    LCD_DC_H();
    LCD_CS_H();
}

static void lcd_send_data(const unsigned char* data, uint16_t size)
{
    LCD_CS_L();
    HAL_SPI_Transmit(HSPI_INSTANCE, data, size,1);
    LCD_CS_H();
}



/**
 * @brief 绘制矩形
 *
 * 在ILI9341屏幕上绘制一个指定位置、大小和颜色的矩形。
 *
 * @param X 矩形左上角的X坐标
 * @param Y 矩形左上角的Y坐标
 * @param Width 矩形的宽度
 * @param Height 矩形的高度
 * @param Colour 矩形的颜色
 */
void ILI9341_Draw_Rectangle(uint16_t X, uint16_t Y, uint16_t Width, uint16_t Height, uint16_t Colour)
{
    // 检查X、Y坐标是否超出屏幕范围
    if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT)) return;

    // 调整宽度和高度以适应屏幕尺寸
    if ((X + Width - 1) >= LCD_WIDTH)
    {
        Width = LCD_WIDTH - X;
    }
    if ((Y + Height - 1) >= LCD_HEIGHT)
    {
        Height = LCD_HEIGHT - Y;
    }

    // 防止宽度或高度为0的情况
    if (Width == 0 || Height == 0) return;

    // 设置地址区域
    ILI9341_Set_Address(X, Y, X + Width - 1, Y + Height - 1);

    // 绘制颜色
    ILI9341_Draw_Colour_Burst(Colour, Height * Width);
    //ILI9341_Draw_Colour(Colour);
}


/**
 * @brief 在ILI9341屏幕上绘制水平线
 *
 * 在ILI9341屏幕的指定位置绘制一条水平线，并指定线的颜色和宽度。
 *
 * @param X 水平线的起始X坐标
 * @param Y 水平线的起始Y坐标
 * @param Width 水平线的宽度
 * @param Colour 水平线的颜色
 */
void ILI9341_Draw_Horizontal_Line(uint16_t X, uint16_t Y, uint16_t Width, uint16_t Colour)
{
    // 验证输入的有效性
    if ((X >= LCD_WIDTH) || (Y >= LCD_HEIGHT) || (Width == 0)) {
        return;
    }

    // 调整宽度以适应屏幕边界
    if ((X + Width - 1) >= LCD_WIDTH) {
        Width = LCD_WIDTH - X;  // 确保宽度不会超出屏幕
    }

    // 绘制水平线
    ILI9341_Set_Address(X, Y, X + Width - 1, Y);
    ILI9341_Draw_Colour_Burst(Colour, Width);
}


/**
 * @brief 在ILI9341屏幕上绘制垂直线
 *
 * 在ILI9341液晶屏幕上从指定的起点开始，绘制指定高度和颜色的垂直线。
 *
 * @param X 垂直线起点的X坐标
 * @param Y 垂直线起点的Y坐标
 * @param Height 垂直线的高度
 * @param Colour 垂直线的颜色
 */
void ILI9341_Draw_Vertical_Line(uint16_t x, uint16_t y, uint16_t height, uint16_t colour)
{
    // 验证输入是否合理
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT || height == 0) {
        return;
    }

    // 确保高度不会超出屏幕范围
    if ((y + height) > LCD_HEIGHT) {
        height = LCD_HEIGHT - y;  // 直接设置正确的高度
    }

    // 绘制线条
    ILI9341_Set_Address(x, y, x, y + height - 1);
    ILI9341_Draw_Colour_Burst(colour, height);
}


/**
 * @brief 在ILI9341屏幕上绘制一条直线
 *
 * 在ILI9341屏幕上从指定的起点到终点绘制一条直线，并指定线的颜色。
 *
 * @param x1 直线起点的X坐标
 * @param y1 直线起点的Y坐标
 * @param x2 直线终点的X坐标
 * @param y2 直线终点的Y坐标
 * @param colour 直线的颜色
 */
void ILI9341_Draw_Line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t colour)
{
    int16_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
    int16_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
    int16_t err = dx + dy, e2;  // error value e_xy

    while (true) {
        // 绘制当前点
        if (dx == 0 && dy == 0) {  // 如果是单个点
            ILI9341_Set_Address(x1, y1, x1, y1);
            ILI9341_Draw_Colour_Burst(colour, 1);
        } else if (dx == 0) {  // 如果是垂直线
            ILI9341_Draw_Vertical_Line(x1, y1, 1, colour);
        } else if (dy == 0) {  // 如果是水平线
            ILI9341_Draw_Horizontal_Line(x1, y1, 1, colour);
        } else {  // 斜线
            ILI9341_Set_Address(x1, y1, x1, y1);
            ILI9341_Draw_Colour_Burst(colour, 1);
        }

        if (x1 == x2 && y1 == y2) break;  // 如果到达终点则退出循环

        e2 = 2 * err;
        if (e2 >= dy) {  // error value exceed dx?
            if (x1 == x2) break;  // 如果到达终点则退出循环
            err += dy; x1 += sx;
        }
        if (e2 <= dx) {  // error value exceed -dy?
            if (y1 == y2) break;  // 如果到达终点则退出循环
            err += dx; y1 += sy;
        }
    }
}





